%{
#include <stdio.h>
#include <assert.h>

typedef enum {
    typeString,
    typeInt,
    typeFloat,
    typeJson,
    typeJsonArray
} PropertyType;

typedef struct{
	FILE *f;
	char *className;
} File;

char *lastClass = NULL;
File fStack[100];
int stackPos = -1;

FILE *rootHeaderFile = NULL;

void pushFILE(File f){
	assert(stackPos < 100);
	fStack[++stackPos] = f;
}
File popFILE(){
	assert(stackPos >= 0);
	File f = fStack[stackPos--];
	lastClass = f.className;
	return f;
}
File lastFILE(){
	if(stackPos == -1){
		File f;
		f.className = "JSONModel";
		f.f = stdout;
		return f;
	}
	return fStack[stackPos];
}
int stackItemCount(){
	return stackPos + 1;
}
int isRoot(){
	return stackPos == 0;
}

int isArray = 0;
int isValue = 0;
int hasPrintInArray = 0;
char *curKey = NULL;

void printStart()
{
	File f;
	strcat(curKey, "Data");
	f.className = curKey;
	char *fn = strdup(curKey);
	f.f = fopen(strcat(fn,".h"), "w");

	fn = strdup(curKey);
	FILE *imp = fopen(strcat(fn, ".m"), "w");
	fprintf(imp,"\n@implementation %s",curKey);
	fprintf(imp,"\n\n\n@end\n",curKey);
	fclose(imp);

	fprintf(f.f,"#include \"JSONModel.h\"\n\n");
	fprintf(f.f,"@interface %s : JSONModel\n\n",curKey);
	pushFILE(f);
}

void printEnd()
{
	FILE *f = popFILE().f;
	fprintf(f, "\n@end\n\n");
	fclose(f);
}

void printProperty(char *s, PropertyType type)
{
    if(hasPrintInArray){
        return;
    }
	FILE *f = lastFILE().f;
    switch(type){
        case typeString:
            { fprintf(f,"@property (strong, nonatomic) NSString *%s;\n", s); }
            break;
        case typeInt:
            { fprintf(f,"@property (assign, nonatomic) NSInteger %s;\n",s);}
            break;
        case typeFloat:
            { fprintf(f,"@property (assign, nonatomic) CGFloat %s;\n",s);}
            break;
        case typeJson:
            { fprintf(f,"@property (strong, nonatomic) %s *%s;\n",lastClass,s); }
            break;
        case typeJsonArray:
            { fprintf(f,"@property (strong, nonatomic) NSArray<%s *> *%s;\n",lastClass,s);}
            break;
        defalut:
			break;
    }
}

%}

%union {
	char *strval;
}

%token L_BRACKET R_BRACKET
%token LM_BRACKET RM_BRACKET
%token COMMA COLON
%token <strval> NUM_INT NUM_FLOAT ANY_STRING

%type <strval> startPairs
%%
json:jsonItem
	|jsonArray
	;
jsonItem: 
		|startJson pairsList endJson 
		;
jsonArray:startJsonArray jsonItemList endJsonArray 
		 ;
startJson:L_BRACKET {
		 if(!isArray){
			 printStart();
		 }
			 }
endJson:R_BRACKET	{
		 if(!isArray){
			printEnd();
		}else{
			hasPrintInArray = 1;
		}
			}
startJsonArray:LM_BRACKET {
			  isArray = 1;
			  hasPrintInArray = 0;
			  printStart();}
endJsonArray:RM_BRACKET	{
			isArray = 0; 
			hasPrintInArray = 0;
			printEnd();}

jsonItemList:jsonItem
			|jsonItemList COMMA jsonItem
			;
pairsList:
		 |pairs
		 |pairsList COMMA pairs
		 ;

pairs:
	 |startPairs ANY_STRING { printProperty($1,typeString); }
	 |startPairs NUM_INT { printProperty($1,typeInt); }
	 |startPairs NUM_FLOAT { printProperty($1,typeFloat); }
	 |startPairs jsonItem { printProperty($1,typeJson); }
	 |startPairs jsonArray { printProperty($1,typeJsonArray); }
	 ;
startPairs:ANY_STRING COLON { isValue = 1; curKey = strdup($1); $$ = $1;printf("curKey:%s\n",$1);}
%%
int main(int argc, char **argv)
{
	if(argc > 1){
		curKey = argv[1];
	}else{
		fprintf(stderr, "请输入一个参数作为json类名\n");
		exit(0);
	}
	yyparse();	
	return 0;
}

yyerror(char *s)
{
	fprintf(stderr, "error: %s\n",s);
}

